package com.pointi.vasEngine;

import java.util.ArrayList;

import com.pointi.emoTools.emoConfig;
import com.pointi.emoTools.vasData;
import com.pointi.emoTools.vasUnit;

public class vasCorrectionFilter
{
	//____________________________________________________________________________________________________
	// Voice Engine Filter

	emoConfig eCONF ;
	
	public vasCorrectionFilter(emoConfig eCONF)
	{
		this.eCONF = eCONF ;
	}

	//____________________________________________________________________________________________________
	// Fix Voice Section
	
	public void fnSectionFixFilter(ArrayList<int[]> section_group, ArrayList<vasUnit> vu_1s)
	{
		for (int i=0; i<section_group.size(); i++)
		{
			if (eCONF.FILTER_STRENGTH() == emoConfig.FILTER_STRENGTH_VOICE_ONLY || eCONF.FILTER_STRENGTH() == emoConfig.FILTER_STRENGTH_ALL)
			{
				if (section_group.get(i)[1] == eCONF.SF_TARGET_CNT())
				{
					/*/ FILTER TARGET /*/
					if (i == 0)
					{
						/*/ [01] FIRST INDEX /*/
					}
					else if (i == (section_group.size()-1))
					{
						/*/ [02] LAST INDEX /*/
						if (section_group.get(i-1)[1] >= eCONF.SF_NEIGHBOR_CNT())
						{
							section_group.get(i-1)[1]++ ;
							section_group.get(i)[0] = -1 ;
							section_group.get(i)[1] = -1 ;
						}
					}
					else 
					{
						/*/ [03] NORMAL INDEX /*/
						if (section_group.get(i)[0] == 0)
						{
							/*/ [03][A] NONVOICE /*/
							if(eCONF.FILTER_STRENGTH() == emoConfig.FILTER_STRENGTH_ALL)
							{
								if (section_group.get(i-1)[0] == section_group.get(i+1)[0])
								{
									section_group.get(i+1)[1] += section_group.get(i-1)[1] + 1 ;
									section_group.get(i-1)[0] = -1 ;
									section_group.get(i-1)[1] = -1 ;
									section_group.get(i)[0] = -1 ;
									section_group.get(i)[1] = -1 ;
								}
								else
								{
									if (section_group.get(i-1)[1] > section_group.get(i+1)[1])
									{
										section_group.get(i)[0] = section_group.get(i-1)[0] ;
										section_group.get(i)[1] = (section_group.get(i-1)[1] + 1) ;
										section_group.get(i-1)[0] = -1 ;
										section_group.get(i-1)[1] = -1 ;
									}
									else if (section_group.get(i-1)[1] < section_group.get(i+1)[1])
									{
										section_group.get(i+1)[1]++ ;
										section_group.get(i)[0] = -1 ;
										section_group.get(i)[1] = -1 ;
									}
									else
									{
										int LEFT = (vu_1s.get(i-1).voice1_cnt() >= vu_1s.get(i-1).voice2_cnt())? vu_1s.get(i-1).voice1_cnt() : vu_1s.get(i-1).voice1_cnt() ; 
										int RIGHT = (vu_1s.get(i+1).voice1_cnt() >= vu_1s.get(i+1).voice2_cnt())? vu_1s.get(i+1).voice1_cnt() : vu_1s.get(i+1).voice1_cnt() ; 
										if (LEFT >= RIGHT)
										{
											section_group.get(i)[0] = section_group.get(i-1)[0] ;
											section_group.get(i)[1] = (section_group.get(i-1)[1] + 1) ;
											section_group.get(i-1)[0] = -1 ;
											section_group.get(i-1)[1] = -1 ;
										}
										else
										{
											section_group.get(i+1)[1]++ ;
											section_group.get(i)[0] = -1 ;
											section_group.get(i)[1] = -1 ;
										}
									}
								}
							}
						}
						else
						{
							/*/ [03][B] VOICE /*/
							if (section_group.get(i-1)[0] == section_group.get(i+1)[0])
							{
								section_group.get(i+1)[1] += (section_group.get(i-1)[1] + 1) ;
								section_group.get(i-1)[0] = -1 ;
								section_group.get(i-1)[1] = -1 ;
								section_group.get(i)[0] = -1 ;
								section_group.get(i)[1] = -1 ;
							}
							else
							{
								if (section_group.get(i-1)[0] == 0 && section_group.get(i+1)[1] >= eCONF.SF_NEIGHBOR_CNT())
								{
									section_group.get(i+1)[1]++ ;
									section_group.get(i)[0] = -1 ;
									section_group.get(i)[1] = -1 ;
								}
								else if (section_group.get(i+1)[0] == 0 && section_group.get(i-1)[1] >= eCONF.SF_NEIGHBOR_CNT())
								{
									section_group.get(i)[0] = section_group.get(i-1)[0] ;
									section_group.get(i)[1] = (section_group.get(i-1)[1] + 1) ;
									section_group.get(i-1)[0] = -1 ;
									section_group.get(i-1)[1] = -1 ;
								}
							}
						}
					}
				}
				else if (section_group.get(i)[1] > 1 && i > 0)
				{
					/*/ EXCEPTION /*/
					if (section_group.get(i-1)[0] == section_group.get(i)[0])
					{
						/*/ SERIAL SECTION /*//** 직전 사이클의 필터링 결과, 교차하지 않고 연속된 클러스터가 발생하면 두 클러스터를 통합한다 **/
						section_group.get(i)[1] += section_group.get(i-1)[1] ;
						section_group.get(i-1)[0] = -1 ;
						section_group.get(i-1)[1] = -1 ;
					}
				}				
			}
		}
		//// CLEAR EMPTY FRAME //
		/** 필터링의 병합 과정에 의해 비어버린 자리를 제거한다 **/
		int v = 0 ;
		boolean loop = true ;
		while(loop)
		{
			if (v == section_group.size()) break ;
			if (section_group.get(v)[0] == -1)
			{
				section_group.remove(v) ;
			}
			else { v++ ; }
		}
	}

	// ____________________________________________________________________________________________________
	// FILTER. A + B // Average & Threshold // 2014.05.21

	public void fnLayeredFilter(ArrayList<vasUnit> inData, double [] inAVG)
	{
		int TV1 = 0, V1 = 0, HV1 = 0 ;
		int TV2 = 0, V2 = 0, HV2 = 0 ;
		int NV = 0 ;

		for(int i=0; i<inData.size(); i++) {
			V1 = inData.get(i).voice1_cnt() ;
			V2 = inData.get(i).voice2_cnt() ;
			NV = inData.get(i).nonvoice_cnt() ;

			// FILTER (A)
			int ID = 0 ; // 1:V1 10:V2 11:V1 or V2
			if(V1 <= inAVG[0] && V1 != 0) ID += 1 ;
			if(V2 <= inAVG[1] && V2 != 0) ID += 10 ;

			if((V1 >= V2 && ID == 11) || ID == 10) { V1 += V2 ; V2 = 0 ; }
			else { V2 += V1 ; V1 = 0 ; }

			// FILTER (B)
			if(V1 < eCONF.CF_L2_THD() && V1 != 0) { NV += V1 ; V1 = 0 ; }
			if(V2 < eCONF.CF_L2_THD() && V2 != 0) { NV += V2 ; V2 = 0 ; }

			// FILTER (C)
			if((i > 0) && ((i+1) < inData.size())) {
				TV1 = inData.get(i-1).voice1_cnt() ; //TAIL
				TV2 = inData.get(i-1).voice2_cnt() ;
				HV1 = inData.get(i+1).voice1_cnt() ; //HEAD
				HV2 = inData.get(i+1).voice2_cnt() ;

				if(TV1 == 0 && V1 != 0 && HV1 == 0) {
					if(V2 == 0 && (TV2 == 0 || HV2 == 0)) NV += V1 ;
					else V2 += V1 ;
					V1 = 0 ;
				}
				if(TV2 == 0 && V2 != 0 && HV2 == 0) {
					if(V1 == 0 && (TV1 == 0 || HV1 == 0)) NV += V2 ;
					else V1 += V2 ;
					V2 = 0 ;
				}
			}

			// UPDATE
			inData.get(i).voice1_cnt(V1) ;
			inData.get(i).voice2_cnt(V2) ;
			inData.get(i).nonvoice_cnt(NV) ;
			inData.get(i).fnCalculateIndex() ;
		}
	}

	// ____________________________________________________________________________________________________
	// FILTER. C // Noise Reduction // Correct Clustering Error

	public void fnNoiseReduction(ArrayList<vasData> inData)
	{
		vasFilterData HeadBuffer = new vasFilterData() ;
		vasFilterData BodyBuffer = new vasFilterData() ;
		vasFilterData TailBuffer = new vasFilterData() ;

		int t_Value = vasFilterData.NULL ;

		// Filtering
		for(int i=0; i<inData.size(); i++) {
			t_Value = inData.get(i).cluster() ;

			if(t_Value != vasData._NONE && t_Value == HeadBuffer.value())
			{
				if(HeadBuffer.value() == vasFilterData.NULL) { HeadBuffer.fnSetFilterData(t_Value, i) ; }
				else { HeadBuffer.add() ; }
			}
			else
			{
				if(TailBuffer.count() != vasFilterData.NULL) // after First Speaker-Block
				{
					if((BodyBuffer.count() <= eCONF.CF_L3_TARGET_CNT())
							&& (TailBuffer.count() >= eCONF.CF_L3_NEIGHBOR_CNT())
							&& (HeadBuffer.count() >= eCONF.CF_L3_NEIGHBOR_CNT()))
					{
						for(int ii=BodyBuffer.index(); ii<(BodyBuffer.index()+BodyBuffer.count()); ii++)
						{
							inData.get(ii).cluster(TailBuffer.value()) ; // REPLACE Data
						}
					}
				}
				if(t_Value == vasData._NONE)
				{
					TailBuffer.fnInitialize() ; 
					BodyBuffer.fnInitialize() ;
					HeadBuffer.fnInitialize() ;
				}
				else
				{
					TailBuffer.fnReplaceData(BodyBuffer) ;
					BodyBuffer.fnReplaceData(HeadBuffer) ;
					HeadBuffer.fnSetFilterData(t_Value, i) ;
				}
			}
			if((i+1) == inData.size()) // last Speaker-Block
			{
				if(TailBuffer.count() != vasFilterData.NULL) // after First Speaker-Block
				{
					if((BodyBuffer.count() <= eCONF.CF_L3_TARGET_CNT())
							&& (HeadBuffer.count() >= eCONF.CF_L3_NEIGHBOR_CNT()))
					{
						for(int ii=BodyBuffer.index(); ii<(BodyBuffer.index()+BodyBuffer.count()); ii++)
						{
							inData.get(ii).cluster(TailBuffer.value()) ; // REPLACE Data
						}
					}
				}
			}
		}
	}
	
	// ____________________________________________________________________________________________________
	// UTILITY

	public double [] fnCalculateAverage(ArrayList<vasUnit> inData)
	{
		double [] voice_avg = new double[2] ;
		int [] voice_sum = new int[2] ;

		voice_sum[0] = 0 ;	voice_sum[1] = 0 ; 
		voice_avg[0] = 0 ;	voice_avg[1] = 0 ;

		for(int i=0; i<inData.size(); i++)
		{
			voice_sum[0] += inData.get(i).voice1_cnt() ;
			voice_sum[1] += inData.get(i).voice2_cnt() ;
		}
		voice_avg[0] = voice_sum[0] / inData.size() ;
		voice_avg[1] = voice_sum[1] / inData.size() ;
		return voice_avg ; 
	}

	// ____________________________________________________________________________________________________
	// EOC
}